﻿using NDF.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using UA.Data;
using UA.Data.Model;
using UA.Framework.Authorization;
using UA.Web.Annotations;

namespace UA.Web.Filters
{
    /// <summary>
    /// 表示 页面功能模块/Controller/Action 细粒度 权限 类型/编码 <see cref="UA.Web.Annotations.ModuleAttribute"/> 定义的过滤器校验操作。
    /// 该属性类型用于一次性添加至 ASP.NET MVC 的过滤器集合 <see cref="GlobalFilterCollection"/> 中。
    /// 该属性类型将用于校验 Controller 或 Action 方法上定义的 <see cref="UA.Web.Annotations.ModuleAttribute"/> 类型 Key/Code 值是否存在并且有效，如果校验失败则会将请求跳转值权限验证失败的提示页面。
    /// </summary>
    public class ModuleAuthorizeAttribute : NDF.Web.Mvc.AuthorizeAttribute
    {
        private UserAccessor _userAccessor;


        public UserAccessor UserAccessor
        {
            get
            {
                if (this._userAccessor == null)
                {
                    this._userAccessor = new UserAccessor();
                }
                return this._userAccessor;
            }
        }

        public Power[] GetPowers()
        {
            return this.UserAccessor.GetPowers(UAAuthentication.UserToken.UserKey.Value);
        }



        protected internal bool HasPower(Guid powerKey, Power[] powers = null)
        {
            if (powers.IsNullOrEmpty())
            {
                powers = this.GetPowers();
            }
            return powers.IsNullOrEmpty() ? false : powers.Any(p => p.Key == powerKey);
        }

        protected internal bool HasPower(string powerCode, Power[] powers = null)
        {
            if (powers.IsNullOrEmpty())
            {
                powers = this.GetPowers();
            }
            return powers.IsNullOrEmpty() ? false : powers.Any(p => p.Code.Equals(powerCode, StringComparison.CurrentCultureIgnoreCase));
        }



        protected internal Power GetPower(Guid powerKey, Power[] powers = null)
        {
            if (powers.IsNullOrEmpty())
            {
                powers = this.GetPowers();
            }
            return powers.IsNullOrEmpty() ? null : powers.FirstOrDefault(p => p.Key == powerKey);
        }

        protected internal Power GetPower(string powerCode, Power[] powers = null)
        {
            if (powers.IsNullOrEmpty())
            {
                powers = this.GetPowers();
            }
            return powers.IsNullOrEmpty() ? null : powers.FirstOrDefault(p => p.Code.Equals(powerCode, StringComparison.CurrentCultureIgnoreCase));
        }

        protected internal Power GetPower(ModuleAttribute model, Power[] powers = null)
        {
            if (powers.IsNullOrEmpty())
            {
                powers = this.GetPowers();
            }
            return powers.IsNullOrEmpty()
                ? null
                : (model.Key.HasValue ? this.GetPower(model.Key.Value, powers) : this.GetPower(model.Code, powers));
        }



        protected override bool AuthorizeCore(AuthorizationContext filterContext)
        {
            bool ret = true;
            Type moduleType = typeof(ModuleAttribute);

            IEnumerable<ModuleAttribute>
                controllerModules = filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(moduleType, inherit: true).OfType<ModuleAttribute>(),
                actionModules = filterContext.ActionDescriptor.GetCustomAttributes(moduleType, inherit: true).OfType<ModuleAttribute>(),
                modules = controllerModules.Union(actionModules);

            Power[] powers = this.GetPowers();

            //ret = modules.All(m => m.Key.HasValue ? this.HasPower(m.Key.Value, powers) : this.HasPower(m.Code, powers));
            ret = modules.All(m => this.ValidatePowerUrl(this.GetPower(m), filterContext));

            return ret;
        }



        protected internal virtual bool ValidatePowerUrl(Power power, AuthorizationContext filterContext)
        {
            if (power == null)
            {
                return false;
            }
            if (power.PowerType == PowerType.Action)
            {
                if (string.IsNullOrWhiteSpace(power.Controller) || string.IsNullOrWhiteSpace(power.Action))
                {
                    return false;
                }
                var urlHelper = new UrlHelper(filterContext.RequestContext);
                string url = urlHelper.Action(power.Action, power.Controller);

                if (!this.ValidateUrl(url, filterContext.HttpContext.Request.Path))
                {
                    return false;
                }
            }
            if (power.PowerType == PowerType.Menu)
            {
                if (!this.ValidateUrl(power.Url, filterContext.HttpContext.Request.Path))
                {
                    return false;
                }
            }
            return true;
        }


        private bool ValidateUrl(string a, string b)
        {
            return string.IsNullOrWhiteSpace(a) || this.ToAppRelative(a).Equals(this.ToAppRelative(b), StringComparison.CurrentCultureIgnoreCase);
        }

        private string ToAppRelative(string virtualPath)
        {
            return VirtualPathUtility.IsAppRelative(virtualPath) ? virtualPath : VirtualPathUtility.ToAppRelative(virtualPath);
        }




        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.Result = new RedirectResult("~/Generic/NoAuth");
        }
    }
}
